Skip to content

Redirect renamed project slugs to current page (#944)#1387

Merged
jonfroehlich merged 1 commit into
masterfrom
944-project-rename-redirects
Jun 24, 2026
Merged

Redirect renamed project slugs to current page (#944)#1387
jonfroehlich merged 1 commit into
masterfrom
944-project-rename-redirects

Conversation

@jonfroehlich

Copy link
Copy Markdown
Member

Summary

Renaming a project changes its short_name (the URL slug), which previously made the old /project/<old-slug>/ URL hard-404 — breaking external links and search results. This came out of the #1142 SEO audit, where /project/mapoutloud/ and /project/mixed-ability-art/ were sitting in Google's "Not found (404)" bucket.

This adds a former-slug → current-page 301 redirect system so renames no longer break URLs, and backfills the known historical renames. Closes #944.

How it works

  • ProjectAlias model (website/models/project_alias.py): maps a retired slug → its Project.
  • Auto-capture (Project.save()): when short_name changes, the old slug is recorded as an alias pointing at the project; a reclaimed slug clears its old alias so it can't self-redirect.
  • View redirect (website/views/project.py): on a slug miss, look up the alias and 301-redirect to the canonical singular /project/<slug>/. A live project always wins over an alias.
  • Uniqueness (clean() on both models): the combined live-slug + alias namespace stays unique, so a slug always resolves to exactly one destination.
  • Admin (ProjectAliasInline): editors see auto-captured aliases and can add historical ones by hand.
  • Seed command (seed_project_aliases, wired into docker-entrypoint.sh): idempotently backfills renames done before auto-capture existed:
    • mapoutloudgeovisally
    • mixed-ability-artartinsight
    • smarthomedhhhomesound

Testing

  • New website/tests/test_project_aliases.py (13 tests): auto-capture on rename, 301 redirect, slug reclaim (no loop), namespace uniqueness, visibility, seed idempotency, and 404 on unknown slugs.
  • Full suite green (531 passed, 8 skipped) via --settings=makeabilitylab.settings_test.
  • Verified live on the dev server: a temporary alias 301-redirected to its project page.

Post-deploy verification

Once on master → test (then tag → prod), confirm:

  • curl -sI .../project/mapoutloud/301/project/geovisally/
  • curl -sI .../project/mixed-ability-art/301/project/artinsight/
  • curl -sI .../project/smarthomedhh/301/project/homesound/

Then re-run GSC "Validate Fix" on the Not found (404) group.

Notes

  • No hand-written migration is committed (per-env website/migrations/ is gitignored; the entrypoint regenerates + the test suite builds from models).
  • Future renames done in admin now record their own aliases automatically — no seed entry needed.

🤖 Generated with Claude Code

Renaming a project changes its short_name (URL slug), which previously made
the old /project/<old-slug>/ URL hard-404 — breaking external links and
search-engine results. This surfaced in the #1142 SEO audit, where
/project/mapoutloud/ and /project/mixed-ability-art/ sat in Google's
"Not found (404)" bucket.

Add a ProjectAlias model (retired slug -> Project). Project.save() captures
the old slug as an alias on rename (and clears a reclaimed slug so it can't
self-redirect); the project view 301-redirects a retired slug to the current
canonical /project/<slug>/. clean() keeps the live-slug + alias namespace
unique so a slug always resolves to one destination. A ProjectAliasInline
lets editors see/add aliases, and the idempotent seed_project_aliases command
(wired into docker-entrypoint.sh) backfills the historical renames done
before auto-capture existed: mapoutloud->geovisally, mixed-ability-art->
artinsight, smarthomedhh->homesound.

Tests: website/tests/test_project_aliases.py (13) covering auto-capture,
301 redirect, slug reclaim, namespace uniqueness, visibility, seed
idempotency, and 404 on unknown slugs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jonfroehlich jonfroehlich merged commit 0a6a0fc into master Jun 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make HomeSound and smarthomedhh link to same view (HomeSound)

1 participant